#include "bbh_linkitem.h"

#define BBH_LINKITEM_INIT(h) h->next = h; h->prev = h;
#define BBH_LINKITEM_ISEMPTY(head) ((head == head->next) && (head == head->prev))
void bbh_linkitem_init(bbh_linkitem_t*head)
{
    BBH_LINKITEM_INIT(head);
}
int bbh_linkitem_isempty(bbh_linkitem_t*head)
{
    return BBH_LINKITEM_ISEMPTY(head) ? 1 : 0;
}
void bbh_linkitem_pushfront(bbh_linkitem_t*head, bbh_linkitem_t*item)
{
    item->next = head->next;
    item->prev = head;

    head->next->prev = item;
    head->next = item;
}
void bbh_linkitem_pushback(bbh_linkitem_t*head, bbh_linkitem_t*item)
{
    item->prev = head->prev;
    item->next = head;

    head->prev->next = item;
    head->prev = item;
}
void bbh_linkitem_remove(bbh_linkitem_t*item)
{
    if (bbh_linkitem_isempty(item))
        return;

    item->next->prev = item->prev;
    item->prev->next = item->next;

    bbh_linkitem_init(item);
}
int  bbh_linkitem_count(bbh_linkitem_t*head)
{
    int r = 0;
    bbh_linkitem_t*item = head->next;

    while (item != head) {
        item = item->next;
        r ++;
    }
    return r;
}

bbh_linkitem_t* bbh_linkitem_popfront(bbh_linkitem_t*head)
{
    if (bbh_linkitem_isempty(head))
        return (bbh_linkitem_t*)0;
    bbh_linkitem_t*it = bbh_linkitem_front(head);
    bbh_linkitem_remove(it);
    return it;
}
bbh_linkitem_t* bbh_linkitem_popback(bbh_linkitem_t*head)
{
    if (bbh_linkitem_isempty(head))
        return (bbh_linkitem_t*)0;
    bbh_linkitem_t*it = bbh_linkitem_back(head);
    bbh_linkitem_remove(it);
    return it;
}
void bbh_linkitem_clear(bbh_linkitem_t*head)
{
    while (bbh_linkitem_popfront(head));
}

void bbh_linkitem_foreach(bbh_linkitem_t*head, void (*cb) (bbh_linkitem_t*, void*), void*data)
{
    bbh_linkitem_t*item = head->next;
    bbh_linkitem_t*next = item->next;

    for (; item != head; item = next, next = next->next) {
        cb(item, data);
    }
}

// void bbh_linkitem_copy(bbh_linkitem_t*from, bbh_linkitem_t*to)
// {
//     if (bbh_linkitem_isempty(from)) {
//         bbh_linkitem_init(to);
//         return;
//     }
//     to->next = from->next;
//     to->prev = from->prev;

//     to->next->prev = to;
//     to->prev->next = to;
// }
void bbh_linkitem_move(bbh_linkitem_t*from, bbh_linkitem_t*to)
{
    if (bbh_linkitem_isempty(from)) {
        bbh_linkitem_init(to);
        return;
    }
    to->next = from->next;
    to->prev = from->prev;

    to->next->prev = to;
    to->prev->next = to;

    bbh_linkitem_init(from);
}
